#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：python_learning 
@File ：svn同步提交.py
@IDE  ：PyCharm 
@Author ：李涵彬
@Date ：2025/2/20 上午10:09 
"""

import os
import subprocess
import time
from datetime import datetime, timezone, timedelta

from git import Repo

# 配置区域
WORK_DIR = r"E:\work_files\projects\cold_rolling_original"
TIME_FILE = os.path.join(WORK_DIR, ".last_svn_sync")
IGNORE_PATTERNS = ['.idea', '.git', '.last_svn_sync']
MAX_RETRIES = 3
RETRY_DELAY = 2

CLEAN_ACTIONS = [
	{'code': '^A', 'check': lambda p: not os.path.exists(p), 'action': 'revert', 'desc': '无效添加'},
	{'code': '^D', 'check': lambda p: os.path.exists(p), 'action': 'revert', 'desc': '无效删除'},
	{'code': '^C', 'action': 'resolve', 'desc': '冲突文件'},
	{'code': '^!', 'action': 'revert', 'desc': '缺失文件'},
	{'code': '^R', 'action': 'revert', 'desc': '替换操作'}
]


def read_last_sync_time():
	"""读取上次同步时间"""
	try:
		with open(TIME_FILE, "r") as f:
			return datetime.fromisoformat(f.read().strip())
	except FileNotFoundError:
		# 默认设置为前一天，时区为UTC+8
		last_sync_time = datetime.now(timezone(timedelta(hours=8))) - timedelta(days=1)
		print(f"未发现找到上次同步时间，默认设置为前一天，时区为UTC+8，时间：{last_sync_time}")
		return last_sync_time


# return datetime(2025, 2, 13, tzinfo=timezone.utc)


def save_sync_time():
	"""保存当前同步时间"""
	with open(TIME_FILE, "w") as f:
		f.write(datetime.now(timezone.utc).isoformat())


def get_git_commits_since(since):
	"""获取Git提交记录"""
	repo = Repo(WORK_DIR)
	return reversed([
		{
			"hash": c.hexsha[:7],
			"message": c.message.strip(),
			"author": c.author.name,
			"time": c.committed_datetime.astimezone(timezone.utc).isoformat()
		}
		for c in repo.iter_commits()
		if c.committed_datetime.astimezone(timezone.utc) > since
	])


def generate_svn_message(commits):
	"""生成详细的SVN提交信息"""
	if not commits:
		return "空提交"

	# 提交信息头
	# header = f"Git提交同步（共{len(commits)}个变更）"
	header = f"提交同步（共{len(commits)}个变更）"

	# 详细变更列表
	details = []
	for idx, commit in enumerate(commits, 1):
		# detail = [
		# 	f"变更 #{idx}",
		# 	f"提交哈希: {commit['hash']}",
		# 	f"作者    : {commit['author']}",
		# 	f"提交时间: {commit['time']}",
		# 	"提交信息:",
		# 	commit['message']
		# ]
		detail = [
			f"提交时间: {commit['time']}",
			"提交信息:",
			commit['message']
		]
		details.append("。".join(detail))

	# 合并信息（保留原始换行）
	return header + "。".join(details)


def full_svn_revert():
	"""执行全局回退"""
	print("[1/4] 执行全局回退...")
	try:
		subprocess.run(
			'svn revert --recursive .',
			shell=True,
			check=True,
			stdout=subprocess.DEVNULL,
			stderr=subprocess.STDOUT
		)
	except subprocess.CalledProcessError as e:
		print(f"全局回退失败: {e}")


def svn_cleanup():
	"""增强清理流程"""
	os.chdir(WORK_DIR)

	# # 第1步：全局回退
	# full_svn_revert()

	# 第2步：基础清理
	print("[2/4] 执行基础清理...")
	subprocess.run('svn cleanup --remove-ignored', shell=True, check=True)

	# 第3步：状态修复
	print("[3/4] 修复无效状态...")
	for action in CLEAN_ACTIONS:
		process_svn_status(action)

	# 第4步：最终确认
	print("[4/4] 验证工作副本...")
	status = subprocess.run(
		'svn status --quiet',
		shell=True,
		capture_output=True,
		text=True
	)
	if status.returncode != 0:
		raise Exception("工作副本状态异常")


def process_svn_status(action_config):
	"""处理特定状态"""
	result = subprocess.run(
		f'svn status | findstr "{action_config["code"]}"',
		shell=True,
		capture_output=True,
		text=True,
		check=False
	)

	items = sorted(
		[line[8:].strip() for line in result.stdout.splitlines()],
		key=lambda x: len(x),
		reverse=True
	)

	for path in items:
		if any(p in path for p in IGNORE_PATTERNS):
			continue

		try:
			if 'check' in action_config and not action_config['check'](path):
				continue

			print(f"处理 {action_config['desc']}: {path}")

			if action_config['action'] == 'revert':
				subprocess.run(
					f'svn revert --depth=infinity "{path}"',
					shell=True,
					check=True
				)
			elif action_config['action'] == 'resolve':
				subprocess.run(
					f'svn resolve --accept=working "{path}"',
					shell=True,
					check=True
				)

			time.sleep(0.2)

		except subprocess.CalledProcessError as e:
			if "not under version control" not in str(e.stderr):
				print(f"处理失败: {path} - {e.stderr}")


def safe_svn_commit(message):
	"""安全提交机制"""
	for attempt in range(1, MAX_RETRIES + 1):
		try:
			print(f"尝试提交（第{attempt}次）...")
			result = subprocess.run(
				f'svn commit -m "{message}"',
				shell=True,
				capture_output=True,
				text=True,
				check=True
			)
			print("提交成功")
			return True
		except subprocess.CalledProcessError as e:
			print(f"提交失败: {e.stderr}")

			if "out of date" in e.stderr:
				print("执行更新...")
				subprocess.run('svn update', shell=True, check=True)
			elif "locked" in e.stderr:
				print("执行清理...")
				subprocess.run('svn cleanup', shell=True, check=True)

			if attempt < MAX_RETRIES:
				print(f"{RETRY_DELAY}秒后重试...")
				time.sleep(RETRY_DELAY)

	print("提交重试次数用尽")
	return False


def svn_commit(message):
	"""提交流程"""
	os.chdir(WORK_DIR)

	try:
		svn_cleanup()

		status = subprocess.run(
			'svn --encoding utf-8 status --quiet',
			shell=True,
			capture_output=True,
			text=True,
			check=True
		)

		valid_changes = [
			line for line in status.stdout.splitlines()
			if line.strip()
			   and not line.startswith(' ')
			   and not any(p in line for p in IGNORE_PATTERNS)
		]

		if not valid_changes:
			print("无有效变更需要提交")
			return

		if not safe_svn_commit(message):
			raise Exception("提交失败")

	except subprocess.CalledProcessError as e:
		error_msg = f"SVN操作失败: {e.stderr}" if e.stderr else str(e)
		raise Exception(error_msg)


def main():
	"""主函数"""
	try:
		last_sync = read_last_sync_time()
		commits = list(get_git_commits_since(last_sync))

		if commits:
			commit_msg = generate_svn_message(commits)
			svn_commit(commit_msg)
			save_sync_time()
			print(f"成功同步 {len(commits)} 个提交")
		else:
			print("无新提交需要同步")

	except Exception as e:
		print(f"同步失败: {str(e)}")
		exit(1)


if __name__ == "__main__":
	main()
